import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
// import App from './App';
// import UseCallback from './hooks/useCallback'
// import reportWebVitals from './reportWebVitals'

// ReactDOM.render(
//   <React.StrictMode>
//     {/* <App /> */}
//     <UseCallback />
//   </React.StrictMode>,
//   document.getElementById('root')
// )

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
// reportWebVitals()

/**
 * 模拟实现 useState Hook：
 *
 * 目标二：支持组件内多次使用 useState，即：提供多个状态。
 *
 * 解决思路：使用**数组**存储这些状态数据；
 * 按照使用 useState 时的**顺序**作为索引，来保存或读取这些数据。
 *
 * 步骤：
 * 1. 将存储状态数据的变量 state 修改为 number 类型的数组，
 *    并设置默认值为 []
 *
 * 2. 创建一个用来记录索引顺序的变量：hookIndex，默认值为 0
 *
 * 3. 在每次调用 useState 最后，将 hookIndex 加 1
 *    目的：为了下一次使用 useState 做准备
 *
 * 4. 将读取和保存状态数据的地方，修改为 state[hookIndex]
 *
 * 5. 在每次组件更新后，重置 hookIndex 的值
 *    目的：这样才能保证在组件更新期间，每次对应的索引都相同
 *
 * 6. 在 useState 内部，使用变量存储当前 hookIndex 的值
 *    然后在 setState 内部，使用该值。
 *    目的：让 setState 中拿到的 hookIndex 就是对应状态的 hookIndex
 */

let state: number[] = []
let hookIndex: number = 0

// 模拟useState
const useState = (initialState: number) => {
  state[hookIndex] = state[hookIndex] || initialState

  // 修改状态的函数
  // 第一次调用 useState hookIndex 值为 0
  // 第二次调用 useState hookIndex 值为 1
  let curHookIndex = hookIndex
  const setState = (value: number) => {
    // console.log('----curHookIndex---', curHookIndex)
    state[curHookIndex] = value

    render()
  }

  // Tuple 类型
  type UseStateTuple = [number, (val: number) => void]

  const res: UseStateTuple = [state[hookIndex], setState]

  hookIndex++
  // console.log('---after hookIndex---', hookIndex)
  return res
}

/**
 * 模拟实现 useEffect Hook：
 *
 * useEffect 的说明：
 * 使用方式： useEffect(() => {}, [])
 *
 * useEffect 会根据依赖项是否改变来决定是否调用 callback
 * 所以，为了判断，需要将 useEffect 的依赖项存在变量 state 中
 *
 * 注意：因为依赖项可以为任意数据，所以，为了简单，我们直接将
 *      修改变量 state 的类型修改为 any[]
 *
 * 步骤：
 * 1. 根据 useEffect Hook 的使用方式，来为其提供参数和返回值。
 *    注意：实际上 useEffect 的回调函数是有返回值的
 *          但是，此处，我们先不处理返回值的问题。
 *
 * 2. 在 useEffect 中获取到上一次的依赖项
 *
 * 3. 在每次调用 useEffect 后，让 hookIndex 加 1
 *    目的：为下一次使用 useEffect 做准备
 *
 * 4. 根据有没有依赖项的值，来决定是否调用 callback
 *    1 如果没有依赖项参数，每次都要调用 callback
 *    2 如果有依赖项参数，只在依赖项改变时调用 callback 即可
 *      1 如果是空数组，可以保证只调用一次即可
 *      2 如果不是空数组，可以保证只在依赖项改变时调用
 *
 * 5. 在调用 callback 后，将新的依赖项保存到变量 state 中
 *    注意：callback 调用才表示依赖项改变了
 *    目的：更新 useEffect 的依赖项，保证下一次检查时，数据正确
 */
let effectIndex = 0
let effectState: any[] = []

// 模拟useEffect
const useEffect = (callback: () => void, deps?: any[]) => {
  // 上一次依赖的值
  let lastDeps = effectState[effectIndex]

  // 是否有依赖项
  let hasNoDeps = false
  // 依赖项是否发生了改变
  let hasDepsChange = false
  if (!deps) {
    // 没有任何依赖
    hasNoDeps = true
  } else {
    // 有依赖
    if (!lastDeps) {
      // 第一次，无论依赖项有没有改变，都需要执行下回调函数
      hasDepsChange = true
    } else {
      hasDepsChange = deps.some((item, index) => {
        return item !== lastDeps[index]
      })
    }
  }

  if (hasNoDeps || hasDepsChange) {
    callback()

    // 更新上一次依赖的值
    effectState[effectIndex] = deps
  }

  effectIndex++
}

function App () {
  const [count, setCount] = useState(100) // state[0] = 100
  const [age, setAge] = useState(18) // state[1] = 18
  console.log('---state---', state)

  useEffect(() => {
    console.log('--no deps--effect1---')
  })

  useEffect(() => {
    console.log('---[]--effect2---')
  }, [])

  useEffect(() => {
    console.log('---count--effect3---', count)
  }, [count])

  useEffect(() => {
    console.log('---age---count--effect4---', age, count)
  }, [age, count])

  const onIncrement = () => {
    setCount(count + 1)
  }

  const onAgeIncrement = () => {
    setAge(age + 1)
  }

  return (
    <div style={{ backgroundColor: 'pink', padding: 10 }}>
      <h1>计数器：{count}</h1>
      <button onClick={onIncrement}>+1</button>

      <hr />
      <p>年龄：{age}</p>
      <button onClick={onAgeIncrement}>年龄+1</button>
    </div>
  )
}

function render () {
  ReactDOM.render(<App />, document.getElementById('root'))

  // 重置 hookIndex 的值
  hookIndex = 0
  // 重置 effectIndex 的值
  effectIndex = 0
}

render()
